#ifndef VECTOR_H_INCLUDED
#define VECTOR_H_INCLUDED

#include "GLOBAL.h"

// Predefine classes:
template<class T> class vec2;
template<class T> class vec3;
template<class T> class vec4;
template<class T> class quat;

/// Template class to define twodimensional vector
template<class T> class vec2{
	public:
		T x, y; ///< coordinates

	public:
		 vec2( );
		 vec2( const T &xx, const T &yy );
		 vec2( const vec2<float> &copy );
		 vec2( const vec2<double> &copy );
		 vec2( const vec3<float> &copy );
		 vec2( const vec3<double> &copy );
		 vec2( T const &xx );
		 ~vec2( ){}

		bool				operator==(const vec2<T> &v );
		bool				operator!=(const vec2<T> &v );
		void				operator-=(const vec2<T> &b );
		void				operator+=(const vec2<T> &b );
		bool				operator==(const vec3<T> &v );
		bool				operator!=(const vec3<T> &v );
		void				operator-=(const vec3<T> &b );
		void				operator+=(const vec3<T> &b );
		void				operator*=(const T &scalar );
		vec2<T>			operator/=(const T &scalar );
		const vec2<T>  operator= (const vec2<T> &v );
		const vec2<T>  operator= (const vec3<T> &v );
		const vec2<T>  operator= (const T &v );
		vec2<T>			operator- (void) const;
		vec2<T>			operator- (const vec2<T> &b )		const;
		vec2<T>			operator+ (const vec2<T> &b )		const;
		vec3<T>			operator- (const vec3<T> &b )		const;
		vec3<T>			operator+ (const vec3<T> &b )		const;
		T const			operator* (const vec2<T> &dot )	const;
		vec2<T>			operator* (const T &scalar )		const;
		vec2<T>			operator/ (const T &scalar )		const;

		T				Angle( const vec2<T> &vector );
		T				AngleRel( const vec2<T> &vector );
		vec2<T>		N();
		vec2<T>     Normalized();
		T const		Length() const;
		T const		Lengthsq() const;

		void Set( T const &xx, T const &yy );
};

/// Template class to define threedimentional vector or color
template<class T> class vec3{
	public:
		T x, y, z; ///< coordinates

	public:
		 vec3( );
		 vec3( T const& xx, T const& yy, T const& zz );
		 vec3( const vec2<float> &copy, const T &zz );
		 vec3( const vec2<double> &copy, const T &zz );
		 vec3( const vec3<float> &copy );
		 vec3( const vec3<double> &copy );
		 vec3( const vec4<float> &copy );
		 vec3( const vec4<double> &copy );
		 vec3( T const &xx );
		 ~vec3( ){}

		bool				operator==(const vec3<T> &v );
		bool				operator!=(const vec3<T> &v );
		void				operator-=(const vec3<T> &b );
		void				operator+=(const vec3<T> &b );
		bool				operator==(const vec2<T> &v );
		bool				operator!=(const vec2<T> &v );
		void				operator-=(const vec2<T> &b );
		void				operator+=(const vec2<T> &b );
		void				operator*=(const T &scalar );
		void				operator/=(const T &scalar );
		const vec3<T>  operator= (const vec3<T> &v );
		const vec3<T>  operator= (const T &v );
		vec3<T>			operator- (void)						const;
		vec3<T>			operator- (const vec3<T> &b )		const;
		vec3<T>			operator+ (const vec3<T> &b )		const;
		vec3<T>			operator- (const vec2<T> &b )		const;
		vec3<T>			operator+ (const vec2<T> &b )		const;
		T const			operator* (const vec3<T> &dot )	const;
		vec3<T>			operator* (const float &scalar )		const;
		vec3<T>			operator* (const double &scalar )		const;
		vec3<T>			operator/ (const T &scalar )		const;
		vec3<T>			operator% (const vec3<T> &cross )const;

		void				operator-=(const vec4<T> &b )						{ *this-=vec3<T>(b); }
		void				operator+=(const vec4<T> &b )						{ *this+=vec3<T>(b); }
		const vec3<T>  operator= (const vec4<T> &v )						{ return *this =vec3<T>(v); }
		vec3<T>			operator- (const vec4<T> &b )		const			{ return *this- vec3<T>(b); }
		vec3<T>			operator+ (const vec4<T> &b )		const			{ return *this+ vec3<T>(b); }
		T const			operator* (const vec4<T> &dot )	const			{ return *this* vec3<T>(dot); }
		vec3<T>			operator% (const vec4<T> &cross )const			{ return *this% vec3<T>(cross); }

		T					Angle( const vec3<T> &vector, vec3<T> &axis_result );
		vec3<T>			N();
		vec3<T>			Normalized();
		T const			Length()										const;
		T const			Lengthsq()									const;

		void				Set( T const &xx, T const &yy, T const &zz );
		vec3<T>			ProjXY() const;
		vec3<T>			ProjXZ() const;
		vec3<T>			ProjYZ() const;

		vec3<T>			Linear( const vec3<T> &vec, const T &cur, const T &begin, const T &end );
		void				Rotate( const vec3<T> &axe, const T &angle );
		ulong				ULong( ) const {
			return tzmRGB( (int)(x*255.0f), (int)(y*255.0f), (int)(z*255.0f) );
		}
};

/// Template class to define fourdimentional vector, color or quaternion
template<class T> class vec4{
	public:
		T x, y, z, w; ///< coordinates

	public:
		 vec4( );
		 vec4( T const& xx, T const& yy, T const& zz );
		 vec4( T const& xx, T const& yy, T const& zz, T const& ww );
		 vec4( const vec2<float> &copy, const vec2<float> &copy2 );
		 vec4( const vec2<double> &copy, const vec2<double> &copy2 );
		 vec4( const vec3<float> &copy );
		 vec4( const vec3<double> &copy );
		 vec4( const vec3<float> &copy, const T &ww );
		 vec4( const vec3<double> &copy, const T &ww );
		 vec4( const vec4<float> &copy );
		 vec4( const vec4<double> &copy );
		 vec4( T const &xx );
		 ~vec4( ){}

		bool				operator==(const vec4<T> &v );
		bool				operator!=(const vec4<T> &v );
		void				operator-=(const vec4<T> &b );
		void				operator+=(const vec4<T> &b );
		void				operator*=(const T &scalar );
		void				operator/=(const T &scalar );
		void				operator= (const vec4<T> &v );
		void				operator= (const T &v );
		vec4<T>			operator- (void)						const;
		vec4<T>			operator- (const vec4<T> &b )		const;
		vec4<T>			operator+ (const vec4<T> &b )		const;
		T const			operator* (const vec4<T> &dot )	const;
		vec4<T>			operator* (const T &scalar )		const;
		vec4<T>			operator/ (const T &scalar )		const;
		vec4<T>			operator% (const vec4<T> &cross )const;

		void				operator-=(const vec3<T> &b )						{		*this-=vec4<T>(b);	 }
		void				operator+=(const vec3<T> &b )						{		 *this+=vec4<T>(b);	 }
		void			   operator= (const vec3<T> &v )						{ x = v.x; y = v.y; z = v.z; w = 0; }
		vec4<T>			operator- (const vec3<T> &b )		const			{ return *this- vec4<T>(b); }
		vec4<T>			operator+ (const vec3<T> &b )		const			{ return *this+ vec4<T>(b); }
		T const			operator* (const vec3<T> &dot )	const			{ return *this* vec4<T>(dot); }
		vec4<T>			operator% (const vec3<T> &cross )const			{ return *this% vec4<T>(cross); }

		T					Angle( const vec4<T> &vector, vec4<T> &axis_result );
		vec4<T>			N();
		vec4<T>			Normalized();
		T const			Length()									const;
		T const			Lengthsq()								const;

		void				Set( T const &xx, T const &yy, T const &zz );
		void				Set( T const &xx, T const &yy, T const &zz, T const &ww );
		vec4<T>			ProjXYZ() const;
		vec4<T>			ProjXY() const;
		vec4<T>			ProjXZ() const;
		vec4<T>			ProjYZ() const;
		vec3<T>			xyz() const;

		vec4<T>			Linear( const vec4<T> &vec, const T &cur, const T &begin, const T &end );
		ulong				ULong( ) const {
			return tzmRGBA( (int)(x*255.0f), (int)(y*255.0f), (int)(z*255.0f), (int)(w*255.0f) );
		}
};

/// Quaternion
template<class T> class quat {
	public:
		T x, y, z, w; ///< coordinates
	public:
		quat( ) : x(0), y(0), z(0), w(1) {}
		quat( const vec3<T> &v1, T v2 );
		quat( const vec4<T> &v1, T ww );
		quat( const T &xx, const T &yy, const T &zz, const T &ww ) : x(xx), y(yy), z(zz), w(ww) {}
		quat( const T &yaw, const T &pitch, const T &roll );
		quat( const vec3<T> &up, const T &yaw, const vec3<T> &right, const T &pitch, const vec3<T> &look, const T &roll );

		void				FromAxisAngle( vec3<T> _kAngle );
		quat<T>			N();
		quat<T>			NormalizedQ() const;
		void				Conjugate();
		quat<T>			Conjugated() const;
		void				LookAt( const vec3<T> &dir );
		void				GetRotation( vec3<T> &axe, T &angle );
		vec3<T>			GetAxis( ) const { return vec3<T>(x,y,z); }
		quat<T>			operator* (const quat<T> &mul )	const;
		vec3<T>			operator* (const vec4<T> &mul )	const			{ return *this* vec3<T>(mul); }
		vec3<T>			operator* (const vec3<T> &mul )	const;
		quat<T>			operator/ (const T &mul )	const;
		void				operator*=(const quat<T> &mul );
		void				operator/=(const T &d );
		void				operator*=(const T &m );
		bool				operator==(const quat<T> &ext )	const;
		bool				operator!=(const quat<T> &ext )	const;

		void				Set( T const &xx, T const &yy, T const &zz );
		void				Set( T const &xx, T const &yy, T const &zz, T const &ww );
};

// Type definitions:
typedef vec2<real> vec2r;
typedef vec2<float> vec2f;
typedef vec2<double> vec2d;
typedef vec2r	uv;

typedef vec3<real> vec3r;
typedef vec3<float> vec3f;
typedef vec3<double> vec3d;

typedef vec4<real> vec4r;
typedef vec4<float> vec4f;
typedef vec4<double> vec4d;

typedef quat<real> quatr;
typedef quat<float> quatf;
typedef quat<double> quatd;

typedef vec3r rgb;
typedef vec4r rgba;



typedef const vec2r	cvec2r;
typedef const vec2f  cvec2f;
typedef const vec2d	cvec2d;
typedef const uv		cuv;

typedef const vec3r	cvec3r;
typedef const vec3f 	cvec3f;
typedef const vec3d	cvec3d;

typedef const vec4r	cvec4r;
typedef const vec4f	cvec4f;
typedef const vec4d	cvec4d;

typedef const quatr	cquatr;
typedef const quatf	cquatf;
typedef const quatd	cquatd;

typedef const rgb		crgb;
typedef const rgba	crgba;


#define  RANDVEC  vec3r( (real)(rand()%1000)*(real)(0.001f), (real)(rand()%1000)*(real)(0.001f), (real)(rand()%1000)*(real)(0.001f) )
#define	UP			vec3r( 0.f, 1.f, 0.f )
#define	DOWN		vec3r( 0.f,-1.f, 0.f )
#define	LEFT		vec3r(-1.f, 0.f, 0.f )
#define  RIGHT		vec3r( 1.f, 0.f, 0.f )
#define  FORWARD	vec3r( 0.f, 0.f, 1.f )
#define  BACKWARD vec3r( 0.f, 0.f,-1.f )
#define	ORIGIN	vec4r( 0.f )
#define	ONEVEC	vec4r( 1.f )
#define	MINUSVEC vec4r(-1.f )
#define	HALFVEC	vec4r( 0.5f )

#define  RED		rgba( 1.f, 0.f, 0.f, 1.f )
#define  GREEN		rgba( 0.f, 1.f, 0.f, 1.f )
#define  BLUE		rgba( 0.f, 0.f, 1.f, 1.f )
#define  ALPHA		rgba( 0.f )
#define	BLACK		rgba( 0.f, 0.f, 0.f, 1.f )
#define  GRAY		rgba( 0.5f, 0.5f, 0.5f, 1.f )
#define  HALPHA	rgba( 0.f, 0.f, 0.f, 0.5f )
#define	WHITE		rgba( 1.f )

#define UVORN		vec2r( 0.f )
#define UVEND		vec2r( 1.f )
#define UVHOR		vec2r( 1.f, 0.f )
#define UVVER		vec2r( 0.f, 1.f )

#define DEFAULT_ORIENTATION quatr( 0,0,0,1 )

// Misc:
#define SMALL_VECTOR (1e-4)


#endif // VECTOR_H_INCLUDED
